#include "AmbientLightRenderer.h"
#include "resource.h"

PositionVertex AmbientLightRenderer::vertices[] = {
		                                           D3DXVECTOR2(1,-1),
		                                           D3DXVECTOR2(-1,-1),
		                                           D3DXVECTOR2(-1,1),
		                                           D3DXVECTOR2(1,1),
	                                              };
DWORD AmbientLightRenderer::indices[6] = {
	                                      0,1,2,
		                                  2,3,0
	                                     };

AmbientLightRenderer::AmbientLightRenderer(void)
{
	contentModule = NULL;
	pDevice = NULL;
	pEffect = NULL;
	pVertexLayout = NULL;
	pTechnique = NULL;
	pVertexBuffer = NULL;
	pIndexBuffer = NULL;
	pColorVariable = NULL;
	pIntensityVariable = NULL;
}

AmbientLightRenderer::~AmbientLightRenderer(void)
{
	UnloadGraphicsContent();
}

void AmbientLightRenderer::UnloadGraphicsContent()
{
	pIntensityVariable = NULL;
	pColorVariable = NULL;
	if (pIndexBuffer != NULL) pIndexBuffer->Release();
	pIndexBuffer = NULL;
	if (pVertexBuffer != NULL) pVertexBuffer->Release();
	pVertexBuffer = NULL;
	if (pVertexLayout != NULL) pVertexLayout->Release();
	pVertexLayout = NULL;
	if (pEffect != NULL) pEffect->Release();
	pEffect = NULL;
	if (contentModule != NULL) FreeLibrary(contentModule);
	contentModule = NULL;
	pDevice = NULL;
}

HRESULT AmbientLightRenderer::LoadGraphicsContent(EnginePointer<ID3D10Device>& pDevice, EnginePointer<ID3D10EffectPool>& pCommonPool)
{
	HRESULT hr;

	this->pDevice = pDevice;

	contentModule = LoadLibrary(L"D3D10EngineContent.dll");
	if (contentModule == NULL) return E_FAIL;

#ifdef _DEBUG
	hr = D3DX10CreateEffectFromResource(contentModule, MAKEINTRESOURCE(AMBIENT_RENDER_EFFECT), NULL, NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS | D3D10_SHADER_DEBUG, D3D10_EFFECT_COMPILE_CHILD_EFFECT, pDevice, pCommonPool, NULL,& pEffect, NULL, NULL);
#else
	hr = D3DX10CreateEffectFromResource(contentModule, MAKEINTRESOURCE(AMBIENT_RENDER_EFFECT), NULL, NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, D3D10_EFFECT_COMPILE_CHILD_EFFECT, pDevice, pCommonPool, NULL,& pEffect, NULL, NULL);
#endif
	if (FAILED(hr)) return hr;

	pTechnique = pEffect->GetTechniqueByName("Render");

	D3D10_PASS_DESC PassDesc;
	pTechnique->GetPassByIndex(0)->GetDesc(&PassDesc);
	hr = pDevice->CreateInputLayout(PositionVertexLayout, PositionVertexNumElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize,& pVertexLayout);
	if (FAILED(hr)) return hr;

	pColorVariable = pEffect->GetVariableByName("Color")->AsVector();
	pIntensityVariable = pEffect->GetVariableByName("Intensity")->AsScalar();

	D3D10_BUFFER_DESC bd;
    bd.Usage = D3D10_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(PositionVertex) * 4;
    bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = vertices;
	hr = pDevice->CreateBuffer(&bd,& InitData,& pVertexBuffer);
    if(FAILED(hr))return hr;

	bd.ByteWidth = sizeof(DWORD) * 6;
    bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
	InitData.pSysMem = indices;
	hr = pDevice->CreateBuffer(&bd,& InitData,& pIndexBuffer);
	if (FAILED(hr)) return hr;

	return S_OK;
}

HRESULT AmbientLightRenderer::Render(list<EnginePointer<AmbientLightComponent>>::iterator lightsBegin, list<EnginePointer<AmbientLightComponent>>::iterator lightsEnd)
{
	HRESULT hr;

	UINT stride = sizeof(PositionVertex);
    UINT offset = 0;
    pDevice->IASetVertexBuffers(0, 1,& pVertexBuffer,& stride,& offset);
	pDevice->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
	pDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
	pDevice->IASetInputLayout(pVertexLayout);

	D3D10_TECHNIQUE_DESC techDesc;
	hr = pTechnique->GetDesc(&techDesc);
	if(FAILED(hr))return hr;

	for (list<EnginePointer<AmbientLightComponent>>::iterator it = lightsBegin; it != lightsEnd; it++)
	{
		hr = pColorVariable->SetFloatVector((*it)->getColor());
		if (FAILED(hr)) return hr;
		hr = pIntensityVariable->SetFloat((*it)->getIntensity());
		if (FAILED(hr)) return hr;

		for (UINT p = 0; p < techDesc.Passes; ++p)
		{
			pTechnique->GetPassByIndex(p)->Apply(0);
			pDevice->DrawIndexed(6, 0, 0);
		}
	}

	return S_OK;
}
